package mybatis_plus;

import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
import com.baomidou.mybatisplus.core.toolkit.support.LambdaMeta;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda;
import org.apache.ibatis.reflection.property.PropertyNamer;

import java.util.List;
import java.util.Map;

/**
 * <p>TableInfo 工具类 增加一些 TableInfoHelper 中没有的方法</p>
 * @author 黄乾坤
 */
public class TableInfoUtils {

	/**
	 * <p>根据表名获取对应的表信息 没有找到返回 null </p>
	 * @param tableName
	 * @return
	 */
	public static TableInfo getTableInfo(String tableName) {
		Assert.notEmpty(tableName, "error: can not find. because tableName is null!");
		List<TableInfo> tableInfos = TableInfoHelper.getTableInfos();
		for (TableInfo tableInfo : tableInfos) {
			if(tableName.equals(tableInfo.getTableName())) {
				return tableInfo;
			}
		}
		return null;
	}
	
	/**
	 * <p>根据 clazz 判断对应的表是否包含 column 字段</p>
	 * @param clazz
	 * @param column
	 * @return
	 */
	public static boolean containsColumn(Class<?> clazz, String column) {
		Assert.notNull(clazz, "error: can not find. because clazz is null!");
		Assert.notEmpty(column, "error: can not find. because column is null!");
		TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz);
		return containsColumn(tableInfo, column);
	}

	/**
	 * <p>根据表名判断对应的表是否包含 column 字段</p>
	 * @param tableName
	 * @param column
	 * @return
	 */
	public static boolean containsColumn(String tableName, String column) {
		Assert.notEmpty(tableName, "error: can not find. because tableName is null!");
		Assert.notEmpty(column, "error: can not find. because column is null!");
		TableInfo tableInfo = getTableInfo(tableName);
		return containsColumn(tableInfo, column);
	}

	/**
	 * <p>根据 tableInfo 判断对应的表是否包含 column 字段</p>
	 * @param tableInfo {@link TableInfoHelper#getTableInfo(Class)}
	 * @param column
	 * @return
	 */
	public static boolean containsColumn(TableInfo tableInfo, String column) {
		if(tableInfo == null) {
			return false;
		}
		List<TableFieldInfo> list = tableInfo.getFieldList();
		for (TableFieldInfo tableFieldInfo : list) {
			if(column.equals(tableFieldInfo.getColumn())) {
				return true;
			}
		}
		return false;
	}

	/**
	 * <p>根据 lambda表达式方式 获取对应的字段名 (找不到 {@link com.baomidou.mybatisplus.annotation.TableField} 注解时返回属性名)</p>
	 * @param sFunction
	 * @return
	 */
	public static <T, R> ColumnCache getColumnName(SFunction<T, R> sFunction){
		LambdaMeta meta = LambdaUtils.extract(sFunction);
		String fieldName = PropertyNamer.methodToProperty(meta.getImplMethodName());
		Class<?> instantiatedClass = meta.getInstantiatedClass();
		Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(instantiatedClass);
		Assert.notNull(columnMap, "can not find lambda cache for this entity [%s]", instantiatedClass.getName());
		ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(fieldName));
		Assert.notNull(columnCache, "can not find lambda cache for this property [%s] of entity [%s]", fieldName, instantiatedClass.getName());
		return columnCache;
	}
	
	/**
	 * <p>获取逻辑删除字段 没有返回 null</p>
	 * @param tableInfo
	 * @return
	 */
	public static TableFieldInfo getLogicDeleteField(TableInfo tableInfo) {
		Assert.notNull(tableInfo, "error: can not find. because tableInfo is null!");
		if(!tableInfo.isLogicDelete()) {
			return null;
		}
		return tableInfo.getFieldList().stream().filter(TableFieldInfo::isLogicDelete).findFirst().orElse(null);
	}
}
